import java.io.File;
import java.io.FileOutputStream;
import javax.imageio.ImageIO

import com.oy.shared.lm.graph.Graph;
import com.oy.shared.lm.graph.GraphEdge;
import com.oy.shared.lm.graph.GraphFactory;
import com.oy.shared.lm.graph.GraphGroup;
import com.oy.shared.lm.graph.GraphNode;
import com.oy.shared.lm.out.GRAPHtoDOT;
import com.oy.shared.lm.out.GRAPHtoDOTtoGIF;


/**
 * This graph constructs and generates the graph
 * 
 * Node produces a leaf, edge connects 2 nodes, and a group produces a box around the nodes
 *
 * A Node needs to call: node.setMemberOf(group) to be a part of a group
 * 
 * Usage - look in main() for usage of this class
 * first, call newGraph(name)
 * then, call nodea = newGraphNode(name, caption)
 * then, call nodea.setShapeComponent(), nodea.setShapeBox() etc.  
 * See Graphviz, Linguine maps docs for more on this
 * then, call newGraphEdge(caption, nodea, nodeb)
 */
class Graphviz
{
    Graph graph
    Logger logger = Logger.getLogger()

    /*
    public def int RECORD = 0;
    public def int BOX = 1;
    public def int ELLIPSE = 2;
    public def int CIRCLE = 3;
    public def int DIAMOND = 4;
    public def int TRIANGLE = 5;
    public def int INVTRIANGLE = 6;
    public def int HEXAGON = 7;
    public def int OCTAGON = 8;
    public def int PARALLELOGRAM = 9;
    public def int COMPONENT = 10;
    public static final int POINT = 11;
    public static final int NOTE = 12;
    public static final int PACKAGE = 13;
    public static final int FOLDER = 14;
    */


    def newGraph(String caption, boolean rotated)
    {
        this.graph = GraphFactory.newGraph()
        this.graph.getInfo().setCaption(caption)
        if(rotated)
            graph.getInfo().setRotated(rotated)
    }

    def newGraphGroup(String caption)
    {
        GraphGroup gg = graph.addGroup()
        gg.getInfo().setModeOutlined()
        gg.getInfo().setCaption(caption)
        gg.getInfo().setLineColor("lightgrey")

        return gg
    }

    def newGraphNode(String name, String label)
    {
        GraphNode gnode = graph.addNode()
        gnode.getInfo().setCaption(name)

        if(label!=null)
            gnode.getInfo().setLabel(label)
        else
            gnode.getInfo().setLabel(name)

        def color = "cyan"
        gnode.getInfo().setFillColor(color)
        gnode.getInfo().setFontSize(9)
        
        //gnode.getInfo().setShapeComponent()
        
        return gnode
    }
    
    def setGraphNodeStyle(GraphNode gNode, 
                            String shape, 
                            String mode, 
                            String lineColor, 
                            String fillColor)
    {
        if(shape!=null)
        {
            if(shape.equalsIgnoreCase("record"))
                gNode.getInfo().setShapeRecord()
            else if(shape.equalsIgnoreCase("box"))
                gNode.getInfo().setShapeBox()
            else if(shape.equalsIgnoreCase("ellipse"))
                gNode.getInfo().setShapeEllipse()
            else if(shape.equalsIgnoreCase("circle"))
                gNode.getInfo().setShapeCircle()
            else if(shape.equalsIgnoreCase("diamond"))
                gNode.getInfo().setShapeDiamond()
            else if(shape.equalsIgnoreCase("triangle"))
                gNode.getInfo().setShapeTriangle()
            else if(shape.equalsIgnoreCase("invtriangle"))
                gNode.getInfo().setShapeInvtriangle()
            else if(shape.equalsIgnoreCase("hexagon"))
                gNode.getInfo().setShapeHexagon()
            else if(shape.equalsIgnoreCase("octagon"))
                gNode.getInfo().setShapeOctagon()
            else if(shape.equalsIgnoreCase("parallelogram"))
                gNode.getInfo().setShapeParallelogram()
            else if(shape.equalsIgnoreCase("component"))
                gNode.getInfo().setShapeComponent()
            else if(shape.equalsIgnoreCase("point"))
                gNode.getInfo().setShapePoint()
            else if(shape.equalsIgnoreCase("note"))
                gNode.getInfo().setShapeNote()
            else if(shape.equalsIgnoreCase("package"))
                gNode.getInfo().setShapePackage()
            else if(shape.equalsIgnoreCase("folder"))
                gNode.getInfo().setShapeFolder()
        }

        if(fillColor != null)
            gNode.getInfo().setFillColor(fillColor)

        if(lineColor != null)
            gNode.getInfo().setLineColor(lineColor)

        if(mode != null)
        {
            if(mode.equalsIgnoreCase("dashed"))
                gNode.getInfo().setModeDashed()
            else if(mode.equalsIgnoreCase("dotted"))
                gNode.getInfo().setModeDotted()
            else if(mode.equalsIgnoreCase("solid"))
                gNode.getInfo().setModeSolid()
            else if(mode.equalsIgnoreCase("bold"))
                gNode.getInfo().setModeBold()
        }
    }




/*    
    def newGraphNodeRecord(String name, String label, attrMap)
    {
        String attrLabel = ""
        attrMap.each { attrKey, attrVal ->
            attrLabel = attrKey + "=" + attrValue + "|"
        }

        def strBuf = new StringBuffer(attrLabel)
        strBuf.setCharAt(str.lastIndexOf('|'), '' as char)
        attrLabel = strBuf.toString()

        
        attrLabel = "{" + label + "|" + attrLabel + "}"

        GraphNode gnode = graph.addNode()
        gnode.getInfo().setCaption(name)


        if(label!=null)
            gnode.getInfo().setLabel(label)
        else
            gnode.getInfo().setLabel(name)


        def color = "cyan"
        gnode.getInfo().setFillColor(color)
        gnode.getInfo().setFontSize(9)

        
        //gnode.getInfo().setShapeComponent()
                
        return gnode
    }
*/



    def newGraphEdge(String caption, GraphNode nodea, GraphNode nodeb)
    {
        GraphEdge edge = graph.addEdge(nodea, nodeb);
        edge.getInfo().setCaption(caption);
        edge.getInfo().setLineColor("lightgrey")
    }

    def genDotFile(String name)
    {
        def dotFileName = "./graphs/" + name + ".dot"

        GRAPHtoDOT.transform(this.graph, new FileOutputStream(new File(dotFileName)))

        return dotFileName;
    }

    def genDotFileInFolder(String name, String folderPath)
    {
        File folder = new File(folderPath)

        //def dotFileName = "./" + folderPath + "/" + name + ".dot"
        def dotFileName = folderPath + "/" + name + ".dot"

        GRAPHtoDOT.transform(this.graph, new FileOutputStream(new File(dotFileName)))

        return dotFileName;
    }

    def genDotImage(String remark, String dotFilePath)
    {
        def imageFilePath = "./imagegraphs/" + new Filename(dotFilePath, new String(java.io.File.separatorChar), '.').filename()+".png"

        def launchStr = "dot -Tpng " + new File(dotFilePath).getCanonicalPath() + " -o " + new File(imageFilePath).getCanonicalPath()
        logger.info("\t|--"+remark+" launching: " + launchStr)

        Process p = Runtime.getRuntime().exec(launchStr)
        def int result = p.waitFor()

        if(result!=0)
            logger.error("\t|--" + remark + "ERROR: creating image from DOT file:" + dotFilePath)
        else
            logger.info("\t|--" + remark + "SUCCESS: created image file:"+ imageFilePath + " from DOT file:" + dotFilePath)

        return dotFilePath + ".gif"
    }

    def genDotImageInFolder(String remark, String dotFilePath, String folderPath)
    {
        File folder = new File(folderPath)

        //def imageFilePath = "./" + folderPath + "/" + new Filename(dotFilePath, new String(java.io.File.separatorChar), '.').filename()+".png"
        //def imageFilePath = folderPath + "/" + new Filename(dotFilePath, new String(java.io.File.separatorChar), '.').filename()+".png"
        def imageFilePath = dotFilePath+".png"

        def launchStr = "dot -Tpng " + new File(dotFilePath).getCanonicalPath() + " -o " + new File(imageFilePath).getCanonicalPath()
        logger.info("\t|--"+remark+" launching: " + launchStr)

        Process p = Runtime.getRuntime().exec(launchStr)
        def int result = p.waitFor()

        if(result!=0)
            logger.error("\t|--" + remark + "ERROR: creating image from DOT file:" + dotFilePath)
        else
            logger.info("\t|--" + remark + "SUCCESS: created image file:"+ imageFilePath + " from DOT file:" + dotFilePath)

        return dotFilePath + ".gif"
    }

    static void main( args)
    {
        Graphviz ggen = new Graphviz()

        ggen.newGraph("Test graph", true)

        def a = ggen.newGraphNode("a", "a")
        a.getInfo().setShapeComponent()

        def b = ggen.newGraphNode("b", "b")
        ggen.newGraphEdge("ab", a, b)

        def ggroup = ggen.newGraphGroup("testgroup")
        ggroup.getInfo().setModeOutlined()
        ggroup.getInfo().setCaption("testgroup")

        a.setMemberOf(ggroup)
        b.setMemberOf(ggroup)

        def dotFilePath = ggen.genDotFile("test")
        ggen.genDotImage(""+dotFilePath)
    }
}
